/**
  **********************************************************************************************************************
  * @file    param.c
  * @brief   该文件提供双向链表功能
  * @author  const_zpc  any question please send mail to const_zpc@163.com
  * @version V1.0
  * @date    2023-05-28
  *
  * @details  功能详细说明：
  *           + 迭代器
  *              + 正向迭代器
  *                 + cotList_Begin(cotList_t *pList);
  *                 + cotList_End(cotList_t *pList);
  *                 + cotList_Next(const cotListItem_t *pListItem);
  *              + 反向迭代器
  *                 + cotList_rBegin(cotList_t *pList);
  *                 + cotList_rEnd(cotList_t *pList);
  *                 + cotList_rNext(const cotListItem_t *pListItem);
  *           + 元素容量
  *                 + cotList_Empty(cotList_t *pList)
  *                 + cotList_Size(cotList_t *pList)
  *           + 元素访问
  *                 + cotList_Front(cotList_t *pList)
  *                 + cotList_Back(cotList_t *pList)
  *           + 元素插入
  *              + 动态节点添加（需要在初始化时提供内存）
  *                 + cotList_Insert(cotList_t *pList, const void *pdata)
  *                 + cotList_PushFront(cotList_t *pList, const void *pdata)
  *                 + cotList_PushBack(cotList_t *pList, const cotListItem_t *pListItem, cotListItem_t *pNewItem)
  *              + 静态节点添加（需要自己定义节点信息后插入）
  *                 + cotList_InsertItem(cotList_t *pList, const cotListItem_t *pListItem, cotListItem_t *pNewItem)
  *           + 元素移除
  *                 + cotList_Erase(cotList_t *pList, const cotListItem_t *pListItem)
  *                 + cotList_Remove(cotList_t *pList, const void *pdata)
  *                 + cotList_RemoveIf(cotList_t *pList, bool (*pfnCondition)(const void *pData))
  *              + 弹出节点
  *                 + cotList_PopFront(cotList_t *pList)
  *                 + cotList_PopBack(cotList_t *pList)
  *           + 内存交换（链表内存交换，减少内存拷贝）
  *                 + cotList_Swap
  *
  **********************************************************************************************************************
  * 源码路径：https://gitee.com/const-zpc/cot.git 具体问题及建议可在该网址填写 Issue
  *
  *
  **********************************************************************************************************************
  */

/* Includes ----------------------------------------------------------------------------------------------------------*/
#include "container/list.h"
#include <stdlib.h>
#include <string.h>


static cotListItem_t *CreatItem(cotList_t *pList)
{
    sizeof(cotList_t);
    cotListItem_t *pItem = NULL;
    cotListItem_t *pNodeBuf = pList->pNodeBuf;

    for (int i = 0; i < pList->nodeBufNum; i++)
    {
        if (pNodeBuf->pNext == NULL && pNodeBuf->pPrev == NULL)
        {
            pItem = pNodeBuf;
            break;
        }

        pNodeBuf++;
    }

    return pItem;
}

static void DestoryItem(cotListItem_t *pItem)
{
    pItem->pNext = NULL;
    pItem->pPrev = NULL;
}

static int Insert(cotList_t *pList, cotListItem_t *pListItem, const void *pdata)
{
    cotListItem_t *pItem = CreatItem(pList);

    if (pItem == NULL)
    {
        return -1;
    }

    pItem->pPrev = pListItem->pPrev;
    pItem->pNext = pListItem;
    pItem->pData = (void *)pdata;

    pListItem->pPrev->pNext = pItem;
    pListItem->pPrev = pItem;
    return 0;
}

static cotListItem_t *Erase(cotList_t *pList, cotListItem_t *pListItem)
{
    cotListItem_t *pNext = pListItem->pNext;
    pListItem->pPrev->pNext = pListItem->pNext;
    pListItem->pNext->pPrev = pListItem->pPrev;

    DestoryItem(pListItem);
    return pNext;
}

static void Clear(cotList_t *pList)
{
    cotListItem_t *pCurItem = pList->node.pNext;

    while (pCurItem != &pList->node)
    {
        pCurItem = Erase(pList, pCurItem);
    }
}

static cotListItem_t *ListBegin(cotList_t *pList)
{
    return pList->node.pNext;
}

static cotListItem_t *ListEnd(cotList_t *pList)
{
    return &pList->node;
}

/**
  * @brief      初始化一个链表
  * 
  * @note       插入数据时会占用“链表节点缓存”创建链表节点信息，但是不包括数据信息
  * @attention  使用 cotList_PushFront、cotList_PushBack和 cotList_Insert 函数插入数据会创建节点；
  *             使用 cotList_InsertItem 函数插入数据不会创建节点；
  * @param[in]  pList       链表句柄
  * @param[in]  pNodeBuf    动态创建链表节点需要使用的缓存
  * @param[in]  nodeBufNum  动态创建链表节点需要使用的节点缓存数目，即最大支持动态创建链表节点的数目
  */
void cotList_Init(cotList_t *pList, cotListItem_t *pNodeBuf,  uint8_t nodeBufNum)
{
    pList->node.pPrev = &pList->node;
    pList->node.pNext = &pList->node;
    pList->node.pData = NULL;
    pList->pNodeBuf = pNodeBuf;
    pList->nodeBufNum = nodeBufNum;
    memset(pList->pNodeBuf, 0, sizeof(cotListItem_t) * nodeBufNum);
}

/**
  * @brief      迭代器开始指针
  * 
  * @param      pList  链表句柄
  * @return     链表元素指针
  */
const cotListItem_t *cotList_Begin(cotList_t *pList)
{
    return ListBegin(pList);
}

/**
  * @brief      迭代器结束指针
  * 
  * @param      pList  链表句柄
  * @return     链表元素指针
  */
const cotListItem_t *cotList_End(cotList_t *pList)
{
    return ListEnd(pList);
}

/**
  * @brief      迭代器下一个元素
  * 
  * @attention  配合 cotList_Begin 和 cotList_End 使用
  * @param      pListItem 链表元素指针
  * @return     链表下一个元素指针
  */
const cotListItem_t *cotList_Next(const cotListItem_t *pListItem)
{
    return pListItem->pNext;
}

/**
  * @brief      反向迭代器开始指针
  * 
  * @param      pList  链表句柄
  * @return     链表元素指针
  */
const cotListItem_t *cotList_rBegin(cotList_t *pList)
{
    return pList->node.pPrev;
}

/**
  * @brief      反向迭代器结束指针
  * 
  * @param      pList  链表句柄
  * @return     链表元素指针
  */
const cotListItem_t *cotList_rEnd(cotList_t *pList)
{
    return &pList->node;
}

/**
  * @brief      反向迭代器下一个元素
  * 
  * @attention  配合 cotList_rBegin 和 cotList_rEnd 使用
  * @param      pListItem 链表元素指针
  * @return     链表下一个元素指针
  */
const cotListItem_t *cotList_rNext(const cotListItem_t *pListItem)
{
    return pListItem->pPrev;
}

/**
  * @brief      返回链表头元素数据指针
  * 
  * @param      pList 链表句柄
  * @return     头元素数据指针
  */
void *cotList_Front(cotList_t *pList)
{
    return pList->node.pNext->pData;
}

/**
  * @brief      返回链表尾元素数据指针
  * 
  * @param      pList 链表句柄
  * @return     尾元素数据指针
  */
void *cotList_Back(cotList_t *pList)
{
    return pList->node.pPrev->pData;
}

/**
  * @brief      判断链表是否为空
  * 
  * @param      pList  链表句柄
  * @return     true   空
  * @return     false  非空
  */
bool cotList_Empty(cotList_t *pList)
{
    return pList->node.pNext == (&pList->node);
}

/**
  * @brief      获取链表元素数目
  * 
  * @param      pList 链表句柄
  * @return     元素数目 
  */
size_t cotList_Size(cotList_t *pList)
{
    cotListItem_t *pCurItem = pList->node.pNext;
    size_t count = 0;

    while (pCurItem != &pList->node)
    {
        count++;
        pCurItem = pCurItem->pNext;
    }

    return count;
}

/**
  * @brief      清除链表所有元素
  * 
  * @param      pList 链表句柄
  * @return     0,成功; -1,失败
  */
int cotList_Clear(cotList_t *pList)
{
    Clear(pList);
    cotList_Init(pList, pList->pNodeBuf, pList->nodeBufNum);
    return 0;
}

/**
  * @brief      在链表某个元素前插入新的元素
  * 
  * @param      pList  链表句柄
  * @param      pListItem 被插入元素的指针
  * @param      pdata  新元素数据(在链表删除该元素之前需要保证地址有效)
  * @return     0,成功; -1,失败
  */
int cotList_Insert(cotList_t *pList, const cotListItem_t *pListItem, const void *pdata)
{
    return Insert(pList, (cotListItem_t *)pListItem, pdata);
}

/**
  * @brief      在链表某个元素前插入新的元素
  * 
  * @attention  需要定义一个链表元素后才能添加
  * @param      pList   链表句柄
  * @param      pListItem 被插入元素的指针
  * @param      pNewItem  新的元素指针(在链表删除该元素之前需要保证地址有效)
  * @return     0,成功; -1,失败
  */
int cotList_InsertItem(cotList_t *pList, const cotListItem_t *pListItem, cotListItem_t *pNewItem)
{
    if (pNewItem->pData ==  NULL)
    {
        return -1;
    }
    pNewItem->pPrev = pListItem->pPrev;
    pNewItem->pNext = (cotListItem_t *)pListItem;

    ((cotListItem_t *)pListItem)->pPrev->pNext = pNewItem;
    ((cotListItem_t *)pListItem)->pPrev = pNewItem;
    return 0;
}

/**
  * @brief      擦除其中一个元素
  * 
  * @param      pList   链表句柄
  * @param      pListItem 被删除元素的节点指针
  * @return     被删除元素的指针的下一个元素
  */
cotListItem_t * cotList_Erase(cotList_t *pList, const cotListItem_t *pListItem)
{
    cotListItem_t *pCurItem = pList->node.pNext;

    while (pCurItem != &pList->node)
    {
        if (pCurItem == pListItem)
        {
            return Erase(pList, (cotListItem_t *)pCurItem);
        }

        pCurItem = pCurItem->pNext;
    }

    return NULL;
}

/**
  * @brief      根据元素数据地址移除
  * 
  * @attention  会删除所有满足条件的元素
  * @param      pList  链表句柄
  * @param      pdata  被删除元素数据地址
  * @return     0,成功; -1,失败 
  */
int cotList_Remove(cotList_t *pList, const void *pdata)
{
    cotListItem_t *pCurItem = pList->node.pNext;

    while (pCurItem != &pList->node)
    {
        if (pCurItem->pData == pdata)
        {
            pCurItem = Erase(pList, pCurItem);
        }
        else
        {
            pCurItem = pCurItem->pNext;
        }
    }

    return 0;
}

/**
  * @brief      根据回调函数满足的条件删除
  * 
  * @attention  会删除所有满足条件的元素
  * @param      pList   链表句柄
  * @param      pfnCondition 回调函数条件(回调形参为节点中的数据指针)
  * @return     0,成功; -1,失败 
  */
int cotList_RemoveIf(cotList_t *pList, bool (*pfnCondition)(const void *pData))
{
    cotListItem_t *pCurItem = pList->node.pNext;

    if (pfnCondition == NULL)
    {
        return -1;
    }

    while (pCurItem != &pList->node)
    {
        if (pfnCondition(pCurItem->pData))
        {
            pCurItem = Erase(pList, pCurItem);
        }
        else
        {
            pCurItem = pCurItem->pNext;
        }
    }

    return 0;
}

/**
  * @brief      推送一个元素到链表头部
  * 
  * @param      pList 链表句柄
  * @param      pdata  新元素数据(在链表删除该元素之前需要保证地址有效)
  * @return     0,成功; -1,失败
  */
int cotList_PushFront(cotList_t *pList, const void *pdata)
{
    Insert(pList, ListBegin(pList), pdata);
}

/**
  * @brief      从链表头部弹出一个元素
  * 
  * @param      pList 链表句柄
  * @return     0,成功; -1,失败
  */
int cotList_PopFront(cotList_t *pList)
{
    Erase(pList, ListBegin(pList));
    return 0;
}

/**
  * @brief      推送一个元素到链表尾部
  * 
  * @param      pList 链表句柄
  * @param      pdata  新元素数据(在链表删除该元素之前需要保证地址有效)
  * @return     0,成功; -1,失败
  */
int cotList_PushBack(cotList_t *pList, const void *pdata)
{
    Insert(pList, ListEnd(pList), pdata);
}

/**
  * @brief      从链表尾部弹出一个元素
  * 
  * @param      pList 链表句柄
  * @return     0,成功; -1,失败
  */
int cotList_PopBack(cotList_t *pList)
{
    Erase(pList, ListEnd(pList)->pPrev);
}

/**
  * @brief      两个链表内存信息进行交换
  * 
  * @param      pList1  链表1
  * @param      pList2  链表2
  * @return     0,成功; -1,失败
  */
int cotList_Swap(cotList_t *pList1, cotList_t *pList2)
{
    cotList_t tmpList = *pList2;

    *pList2 = *pList1;

    if (pList2->node.pNext == &pList1->node)
    {
        pList2->node.pPrev = &pList2->node;
        pList2->node.pNext = &pList2->node;
    }
    else
    {
        pList1->node.pPrev->pNext = &pList2->node;
        pList1->node.pNext->pPrev = &pList2->node;
    }

    *pList1 = tmpList;

    if (pList1->node.pNext == &pList2->node)
    {
        pList1->node.pPrev = &pList1->node;
        pList1->node.pNext = &pList1->node;
    }
    else
    {
        pList1->node.pPrev->pNext = &pList1->node;
        pList1->node.pNext->pPrev = &pList1->node;
    }

    return 0;
}

